﻿/* 
 * Copyright (c) 2009, Jason D. Montgomery
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice, this 
 *   list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright notice, 
 *   this list of conditions and the following disclaimer in the documentation 
 *   and/or other materials provided with the distribution.
 * 
 * * Neither the name of ATGi nor the names of its contributors may be used to 
 *   endorse or promote products derived from this software without specific 
 *   prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Web.UI;
using System.Collections;

namespace DnSecAnalysis
{
    public partial class ViewStateDecoderControl : System.Windows.Forms.UserControl
    {
        private const string INDENT_STRING = "   ";

        public ViewStateDecoderControl()
        {
            InitializeComponent();
        }

        public void Write(string text)
        {
            txtBxOutput.AppendText(text);
        }

        public void ClearText()
        {
            txtBxOutput.Clear();
        }

        public void ParseViewState(string strViewState)
        {
            using (TextWriter tw = new StringWriter())
            {
                LosFormatter los = new LosFormatter();
                object viewState = los.Deserialize(strViewState);

                ParseViewStateGraph(viewState, tw);
                txtBxOutput.AppendText(tw.ToString());
            }
        }
        // ViewState Decoding Logic from MSDN Article
        // http://msdn.microsoft.com/en-us/library/ms972976.aspx
        private void ParseViewStateGraph(object viewState, TextWriter tw)
        {
            ParseViewStateGraph(viewState, 0, string.Empty, tw);
        }

        private void ParseViewStateGraph(object node, int depth, string label, TextWriter tw)
        {
            tw.Write(System.Environment.NewLine);
            if (node == null)
            {
                tw.Write(String.Concat(Indent(depth), label, "NODE IS NULL"));
            }
            else if (node is Triplet)
            {
                tw.Write(String.Concat(Indent(depth), label, "TRIPLET"));
                ParseViewStateGraph(
                  ((Triplet)node).First, depth + 1, "First: ", tw);
                ParseViewStateGraph(
                  ((Triplet)node).Second, depth + 1, "Second: ", tw);
                ParseViewStateGraph(
                  ((Triplet)node).Third, depth + 1, "Third: ", tw);
            }
            else if (node is Pair)
            {
                tw.Write(String.Concat(Indent(depth), label, "PAIR"));
                ParseViewStateGraph(((Pair)node).First, depth + 1, "First: ", tw);
                ParseViewStateGraph(((Pair)node).Second, depth + 1, "Second: ", tw);
            }
            else if (node is ArrayList)
            {
                tw.Write(String.Concat(Indent(depth), label, "ARRAYLIST"));
                // display array values
                for (int i = 0; i < ((ArrayList)node).Count; i++)
                    ParseViewStateGraph(
                      ((ArrayList)node)[i], depth + 1, String.Format("({0}) ", i), tw);
            }
            else if (node.GetType().IsArray)
            {
                tw.Write(String.Concat(Indent(depth), label, "ARRAY "));
                tw.Write(String.Concat("(", node.GetType().ToString(), ")"));
                IEnumerator e = ((Array)node).GetEnumerator();
                int count = 0;
                while (e.MoveNext())
                    ParseViewStateGraph(
                      e.Current, depth + 1, String.Format("({0}) ", count++), tw);
            }
            else if (node.GetType().IsPrimitive || node is string)
            {
                tw.Write(String.Concat(Indent(depth), label));
                tw.Write(node.ToString() + " (" +
                  node.GetType().ToString() + ")");
            }
            else if (node.GetType().IsClass && node.GetType().FullName.Equals("System.Web.UI.IndexedString"))
            {
                IndexedString nodeIndxString = (IndexedString)node;
                tw.Write(String.Concat(Indent(depth), label));
                tw.Write(nodeIndxString.Value + " (" +
                  node.GetType().ToString() + ")");
            }
            else
            {
                tw.Write(String.Concat(Indent(depth), label, "OTHER - "));
                tw.Write(node.GetType().ToString());
            }
        }

        protected virtual string Indent(int depth)
        {
            StringBuilder sb = new StringBuilder(INDENT_STRING.Length * depth);
            for (int i = 0; i < depth; i++)
                sb.Append(INDENT_STRING);

            return sb.ToString();
        }
    }
}
